#include <iostream>
#include <string>
#include <cstring>
#include <memory>
#include <thread>
#include <vector>
#include <fstream>
#include <system_error>
#include <stdexcept>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

class Socket {
private:
    int fd_;

public:
    Socket(int domain, int type, int protocol) {
        fd_ = socket(domain, type, protocol);
        if (fd_ == -1) {
            throw std::system_error(errno, std::generic_category(), "socket creation failed");
        }
    }

    ~Socket() {
        if (fd_ != -1) {
            close(fd_);
        }
    }

    int get() const { return fd_; }
};

class WebServer {
private:
    Socket sock_;
    std::string base_path_ = "/root/Study/Project/MyWeb/vue_myweb/dist";

    void setup_socket(const std::string& ip, uint16_t port) {
        struct sockaddr_in saddr;
        memset(&saddr, 0, sizeof(saddr));
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(port);
        if (inet_pton(AF_INET, ip.c_str(), &saddr.sin_addr) <= 0) {
            throw std::runtime_error("invalid IP address");
        }

        if (bind(sock_.get(), (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
            throw std::system_error(errno, std::generic_category(), "bind failed");
        }

        if (listen(sock_.get(), 5) == -1) {
            throw std::system_error(errno, std::generic_category(), "listen failed");
        }
    }

    std::string get_filename(const std::string& request) const {
        size_t first_space = request.find(' ');
        if (first_space == std::string::npos) return "";

        size_t second_space = request.find(' ', first_space + 1);
        if (second_space == std::string::npos) return "";

        std::string path = request.substr(first_space + 1, second_space - first_space - 1);
        std::cout << "请求路径：" << path << std::endl;

        // 处理前端路由
        if (path.find('.') == std::string::npos) {
            return "/index.html";
        }
        return path;
    }

    std::pair<int, size_t> open_file(const std::string& filename) const {
        std::string full_path = base_path_ + filename;
        int fd = open(full_path.c_str(), O_RDONLY);
        if (fd == -1) return {-1, 0};

        size_t size = lseek(fd, 0, SEEK_END);
        lseek(fd, 0, SEEK_SET);
        return {fd, size};
    }

    void send_response(int client_fd, const std::string& status, 
                      const std::string& content_type, 
                      const std::string& content) const {
        std::string header = 
            "HTTP/1.1 " + status + "\r\n"
            "Server: myweb_beisen\r\n"
            "Content-Type: " + content_type + "\r\n"
            "Content-Length: " + std::to_string(content.size()) + "\r\n"
            "\r\n";
        
        send(client_fd, header.c_str(), header.size(), 0);
        send(client_fd, content.c_str(), content.size(), 0);
    }

    void handle_client(int client_fd) const {
        char buffer[1024] = {0};
        int bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
        if (bytes_read <= 0) {
            close(client_fd);
            return;
        }

        std::string request(buffer);
        std::string filename = get_filename(request);
        if (filename.empty()) {
            send_response(client_fd, "404 Not Found", "text/html", "<h1>404 Not Found</h1>");
            close(client_fd);
            return;
        }

        auto [file_fd, file_size] = open_file(filename);
        if (file_fd == -1) {
            // 尝试发送404页面
            auto [fd404, size404] = open_file("/404.html");
            if (fd404 == -1) {
                send_response(client_fd, "404 Not Found", "text/html", "<h1>404 Not Found</h1>");
            } else {
                std::vector<char> content(size404);
                read(fd404, content.data(), size404);
                send_response(client_fd, "404 Not Found", "text/html", 
                            std::string(content.data(), content.size()));
                close(fd404);
            }
        } else {
            // 确定Content-Type
            std::string content_type = "text/html";
            if (filename.find(".css") != std::string::npos) {
                content_type = "text/css";
            } else if (filename.find(".js") != std::string::npos) {
                content_type = "application/javascript";
            } else if (filename.find(".png") != std::string::npos) {
                content_type = "image/png";
            } else if (filename.find(".ico") != std::string::npos) {
                content_type = "image/x-icon";
            } else if (filename.find(".svg") != std::string::npos) {
                content_type = "image/svg+xml";
            }

            std::vector<char> content(file_size);
            read(file_fd, content.data(), file_size);
            send_response(client_fd, "200 OK", content_type, 
                         std::string(content.data(), content.size()));
            close(file_fd);
        }

        close(client_fd);
        std::cout << "Client disconnected" << std::endl;
    }

public:
    WebServer(const std::string& ip, uint16_t port)
        : sock_(AF_INET, SOCK_STREAM, 0) {
        setup_socket(ip, port);
    }

    void run() {
        std::cout << "Server running..." << std::endl;
        while (true) {
            sockaddr_in client_addr;
            socklen_t client_len = sizeof(client_addr);
            int client_fd = accept(sock_.get(), 
                                  (struct sockaddr*)&client_addr, 
                                  &client_len);
            if (client_fd < 0) continue;

            std::thread([this, client_fd]() {
                handle_client(client_fd);
            }).detach();
        }
    }
};

int main() {
    try {
        WebServer server("192.168.8.224", 80);
        server.run();
    } catch (const std::exception& e) {
        std::cerr << "Server error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}